﻿using System;
using ESRI.ArcGIS.Carto;
using ESRI.ArcGIS.esriSystem;
using ESRI.ArcGIS.Geodatabase;
using ESRI.ArcGIS.Geometry;
using System.Data;

using PlanningGIS.Util.Convertor;
using PlanningGIS.ArcGIS;
using PlanningGIS.Util.Log;
using PlanningGIS.Engine.Controls;

namespace PlanningGIS.DataCheck.model
{
    
    public class ContourDisCheck : Check
    {
        private FeatureDone featureDone;

        public FeatureDone RefreshFeature
        {
            set { featureDone = value; }
        }

        /// <summary>
        /// 等高距一致性检
        /// </summary>
        /// <param name="errType">错误类型</param>
        /// <param name="pFeatLyr">等高线图层</param>
        /// <param name="eleFieldName">高程字段名称</param>
        /// <param name="pPolyline">辅助线</param>
        /// <returns></returns>
        public int Check(string errType, IFeatureLayer pFeatLyr, string eleFieldName, IPolyline pPolyline, double dis)
        {
            IFeatureClass pFeatCls = pFeatLyr.FeatureClass;
            if (pFeatCls.ShapeType != esriGeometryType.esriGeometryPolyline)
            {
                LogHelper.WriteLog("[" + pFeatLyr.Name + "]图层不是线层，检查失败！");
                return -1;
            }

            int indexEle = pFeatCls.FindField(eleFieldName);
            if (indexEle == -1)
            {
                LogHelper.WriteLog("[" + pFeatLyr.Name + "]图层高程属性[" + eleFieldName + "]不存在或设置有误，检查失败！");
                return -1;
            }

            if (pPolyline == null || pPolyline.IsEmpty)
            {
                LogHelper.WriteLog("请先在图面上划一根辅助线。");
                return -1;
            }

            if (dis <= 0)
            {
                LogHelper.WriteLog("等高距应为非负数。");
                return -1;
            }

            ISpatialFilter pSpatialFileter = new SpatialFilterClass();
            pSpatialFileter.Geometry = pPolyline;
            pSpatialFileter.SpatialRel = esriSpatialRelEnum.esriSpatialRelIntersects;
            pSpatialFileter.GeometryField = pFeatCls.ShapeFieldName;
            pSpatialFileter.WhereClause = eleFieldName + " is not null";

            showFakePro(true);
            LogHelper.WriteLog("正在计算需要检查的要素数目...");

            int max = FeatureClassHelper.GetFeatureCountFromLayer(pFeatLyr, pSpatialFileter);// pFeatCls.FeatureCount(pSpatialFileter);

            LogHelper.WriteLog("计算完毕。共有" + max + "个要素参与检查。");
            showFakePro(false);

            if (max < 2)
            {
                LogHelper.WriteLog("至少需要选中两个要素才能进行检查。");
                return -1;
            }

            setProcessBarMax(max);

            IFeatureCursor pFeatCur;
            pFeatCur = pFeatLyr.Search(pSpatialFileter, false);// pFeatCls.Search(pSpatialFileter, false);

            IFeature pFeature;
            pFeature = pFeatCur.NextFeature();

            DataTable table = new DataTable("table");
            DataRow dataRow;
            DataColumn colItemFID = new DataColumn("FID", Type.GetType("System.Int32"));
            DataColumn colItemX = new DataColumn("X", Type.GetType("System.Double"));
            DataColumn colItemY = new DataColumn("Y", Type.GetType("System.Double"));

            table.Columns.Add(colItemFID);
            table.Columns.Add(colItemX);
            table.Columns.Add(colItemY);

            DataView dataView = new DataView(table);

            ITopologicalOperator2 pTopo = pPolyline as ITopologicalOperator2;
            pTopo.IsKnownSimple_2 = false;
            pTopo.Simplify();

            IGeometry pGeometry;
            IGeometryCollection pGeomCln;
            IPoint pPoint;

            showFakePro(true);
            LogHelper.WriteLog("正在对选中的要素进行排序...");

            int count = 0;

            //IGeometryCollection pPntCln;
            IPolyline pPolylineErr;

            while (pFeature != null)
            {
                if (IsStop()) break;

                setProcessBarCurrent(count);
                count++;

                pGeometry = pFeature.ShapeCopy;

                ITopologicalOperator2 pTop2 = pGeometry as ITopologicalOperator2;
                pTop2.IsKnownSimple_2 = false;
                pTop2.Simplify();

                pGeometry.Project(pPolyline.SpatialReference);

                pGeomCln = (IGeometryCollection)pTopo.Intersect(pGeometry, esriGeometryDimension.esriGeometry0Dimension);

                if (pGeomCln == null) continue;
                if (pGeomCln.GeometryCount != 1)
                {
                    LogHelper.WriteLog("辅助线与相交的要素只能有一个交点。\n");
                    setProcessBarCurrent.Invoke(max);
                    return -1;
                }
                pPoint = pGeomCln.get_Geometry(0) as IPoint;

                dataRow = table.NewRow();
                dataRow["FID"] = pFeature.OID;
                dataRow["X"] = pPoint.X;
                dataRow["Y"] = pPoint.Y;
                table.Rows.Add(dataRow);


                DataCheckUtility.ReleaseComObject(pPoint);
                DataCheckUtility.ReleaseComObject(pGeomCln);
                DataCheckUtility.ReleaseComObject(pGeometry);
                DataCheckUtility.ReleaseComObject(pFeature);
                pFeature = pFeatCur.NextFeature();
            }

            DataCheckUtility.ReleaseComObject(pFeatCur);

            dataView.Sort = "X,Y";

            showFakePro(false);

            LogHelper.WriteLog("排序完毕。");
            LogHelper.WriteLog("检查中...");

            int errCount = 0;

            pFeature = pFeatCls.GetFeature(Int32.Parse(dataView[0]["FID"].ToString()));

            IFeature pFeatCompare;

            double elevation;
            double eleCompare;

            pPoint = new PointClass();

            for (int i = 1; i < dataView.Count; i++)
            {
                if (IsStop()) break;

                setProcessBarCurrent(i);

                pFeatCompare = pFeatCls.GetFeature(Int32.Parse(dataView[i]["FID"].ToString()));

                if (pFeature.get_Value(indexEle) == null && StringHelper.CanConvert2Double(pFeature.get_Value(indexEle)) == false)
                {
                    pPoint.PutCoords(Double.Parse(dataView[i - 1]["X"].ToString()), Double.Parse(dataView[i - 1]["Y"].ToString()));
                    RecordListHelper.AddRecordItem(errType, pFeatLyr, null, pFeature, null, pPoint, "高程字段值异常");
                    errCount++;
                    goto NEXTFEATURE;
                    //continue;
                }
                elevation = Double.Parse(pFeature.get_Value(indexEle).ToString());

                if (pFeatCompare.get_Value(indexEle) == null && StringHelper.CanConvert2Double(pFeatCompare.get_Value(indexEle)) == false)
                {
                    if (i == dataView.Count)
                    {
                        pPoint.PutCoords(Double.Parse(dataView[i]["X"].ToString()), Double.Parse(dataView[i]["Y"].ToString()));
                        RecordListHelper.AddRecordItem(errType, pFeatLyr, null, pFeatCompare, null, pPoint, "高程字段值异常");
                        errCount++;
                    }
                    goto NEXTFEATURE;
                    //continue;
                }
                eleCompare = Double.Parse(pFeatCompare.get_Value(indexEle).ToString());

                if (Math.Abs(elevation - eleCompare) != dis)
                {
                    IPoint pPnt1 = new PointClass();
                    pPnt1.PutCoords(Double.Parse(dataView[i - 1]["X"].ToString()), Double.Parse(dataView[i - 1]["Y"].ToString()));
                    IPoint pPnt2 = new PointClass();
                    pPnt2.PutCoords(Double.Parse(dataView[i]["X"].ToString()), Double.Parse(dataView[i]["Y"].ToString()));
                    pPolylineErr = new PolylineClass();
                    pPolylineErr.FromPoint = pPnt1;
                    pPolylineErr.ToPoint = pPnt2;

                    RecordListHelper.AddRecordItem(errType, pFeatLyr, null, pFeature, pFeatCompare, pPolylineErr, "等高距：" + Math.Abs(elevation - eleCompare));
                    errCount++;
                }

            NEXTFEATURE:
                if (featureDone != null) featureDone(pFeature);
                pFeature = pFeatCompare;
            }

            if (featureDone != null) featureDone(pFeature);
            finishPro();

            DataCheckUtility.ReleaseComObject(pFeature);
            DataCheckUtility.ReleaseComObject(pPoint);

            LogHelper.WriteLog("等高距检查结束。共发现" + errCount + "处错误！\n");
            return errCount;
        }

    }
}
